Luogu P1047 校门外的树 Posted on 2017-12-27 | In 题解 | Words count in article: 591 | Reading time ≈ 3 首先,如题目算法标签所言,线段树(其实也是杂技写法) 不多赘述,建树、修改、查询一气呵成,就算是杂技,也要做杂技中的豪杰(逃) 代码如下: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788#include <bits/stdc++.h>#define N 2000010using namespace std;struct node{ int left,right; long long val,sum;};struct node a[4*N];int data[N],n,m,x,y,b;long long z;void pushup(int p){ a[p].sum=a[2*p].sum+a[2*p+1].sum;}void pushdown(int p){ if(a[p].val!=-1) { a[2*p].val=a[p].val; a[2*p+1].val=a[p].val; a[2*p].sum=(a[2*p].right-a[2*p].left+1)*a[p].val; a[2*p+1].sum=(a[2*p+1].right-a[2*p+1].left+1)*a[p].val; a[p].val=-1; }}//pushup、pushdown是基本操作,不多讲void build(int p,int l,int r){ a[p].left=l; a[p].right=r; a[p].val=-1; if(l==r) { a[p].sum=data[l]; return; } int mid=(a[p].left+a[p].right)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); a[p].sum=a[2*p].sum+a[2*p+1].sum;}//建树也很简单long long query(int p,int l,int r){ if(a[p].left==l&&a[p].right==r) return a[p].sum; pushdown(p); int mid=(a[p].left+a[p].right)/2; if(r<=mid) return query(2*p,l,r); else if(l>mid) return query(2*p+1,l,r); else return query(2*p,l,mid)+query(2*p+1,mid+1,r);}//查询void change(int p,int l,int r,long long d){ if(a[p].left==l&&a[p].right==r) { a[p].sum=(l-r+1)*d; a[p].val=0; return; } pushdown(p); int mid=(a[p].left+a[p].right)/2; if(r<=mid) change(2*p,l,r,d); else if(l>mid) change(2*p+1,l,r,d); else { change(2*p,l,mid,d); change(2*p+1,mid+1,r,d); } pushup(p);}//此函数是与模板唯一的差别,将砍掉的树的值赋为0,这样就只需查询根节点处的区间和了int main(){ cin>>n>>m; for(int i=1;i<=n+1;i++) data[i]=1;//将每个位置的初值赋为1,方便查询时只查根节点。值得注意的是,由于这里是算了0这个位置的,所以n、x、y都要相应的加1 build(1,1,n+1); for(int i=1;i<=m;i++) { cin>>x>>y; change(1,x+1,y+1,0); } cout<<query(1,1,n+1); return 0;} 比较简单不多说,具体注释看代码